package demo.using;

import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;

public class BST1 <E extends Comparable<E>>{
    private class Node{
        public Node left,right;
        public E e;
        public Node(E e){
            this.e=e;
            left=null;
            right=null;
        }
    }
    public int size;
    public Node root;
    public BST1(){
        root=null;
        size=0;
    }
    public int size(){
        return size;
    }
    public boolean isEmpty(){
        return size==0;
    }
    //向树中添加元素
    public void add(E e){
//      if(root==null){
//          root=new Node(e);
//          size++;
//          return;
//      }
        root=add(root,e);

    }
    private Node add(Node node,E e){
        if(node==null){
            size++;
            return new Node(e);
        }
        else if(e.compareTo(node.e)<0){
            Node left=add(node.left,e);//如果小于树中的元素，则向该节点的左子树插入元素，此节点为根节点，
            //再继续判断是否为空，如果是直接创建新节点并将值插入
            size++;
        }
        else if(e.compareTo(node.e)>0){
            Node right=add(node.right,e);
            size++;
        }
        return node;
    }
    //查询元素
    public boolean contains(E e){
        return contains(root,e);
    }
    private boolean contains(Node node,E e){
        if(node==null){
            return false;
        }
        if(e.compareTo(node.e)==0){
            return true;
        }
        else if(e.compareTo(node.e)>0){
            return contains(node.right,e);

        }
        else if(e.compareTo(node.e)<0){
            return contains(node.left,e);
        }
        return false;

    }
    //遍历元素--前序遍历---先遍历节点元素--》左子树--》右子树
    public void preOrder(){
        preOrder(root);
    }
    public void preOrder(Node node){
        if(node==null){
            return;
        }
        System.out.println(node.e);
        preOrder(node.left);
        preOrder(node.right);
    }
    //前序遍历非递归----利用栈结构
    public void preOrderNR(){
        Stack<Node> stack=new Stack<>();
        stack.push(root);
        while(!stack.isEmpty()){
            Node cur=stack.pop();
            System.out.println(cur.e);
            if(cur.left!=null){
                stack.push(cur.right);
            }
            if(cur.left!=null){
                stack.push(cur.left);
            }
        }

    }
    //  前序遍历---层序遍历（广度优先遍历）-队列
    public void leveOrder(){
        Queue<Node> q=new LinkedList<>();
        q.add(root);
        while(!q.isEmpty()){
            Node cur=q.remove();
            System.out.println(cur.e);
            if(cur.left!=null){
                q.add(cur.left);

            }
            if(cur.right!=null){
                q.add(cur.right);
            }
        }

    }
    //中序遍历--先遍历左子树--》节点元素--》右子树
    public void inOrder(){
        inOrder(root);
    }
    public void  inOrder(Node node){
        if(node==null){
            return;
        }
        inOrder(node.left);
        System.out.println(node.e);
        inOrder(node.right);
    }
    //后序遍历--先遍历左子树--》右子树--》节点元素
    public void postOrder(){
        postOrder(root);
    }
    public void postOrder(Node node){
        if(node==null){
            return;
        }
        postOrder(node.left);
        postOrder(node.right);
        System.out.println(node.e);
    }
    //寻找最小节点
    public E minimum(){
        if(size==0){
            throw new IllegalArgumentException("树为空！");
        }
        Node minNode=minimum(root);
        return minNode.e;
    }
    private Node minimum(Node node){
        if(node.left==null){
            return node;
        }
        return minimum(node.left);
    }
    //寻找最大节点
    public E maximum(){
        if(size==0){
            throw new IllegalArgumentException("树为空！");
        }
        Node maxNode=maximum(root);
        return maxNode.e;
    }
    private Node maximum(Node node){
        if(node.right==null){
            return node;
        }
        return maximum(node.right);
    }
    //删除二叉树中最小值所在的节点，并返回这个值
    public E removeMin(){
        E ret=minimum();//调用寻找最小节点的方法（其中已经包含根结点）
        root=removeMin(root);
        return ret;
    }
    private Node removeMin(Node node){
        //删除以node为跟根的二叉树最小节点
        if(node.left==null){
            Node rightNode=node.right;
            node.right=null;
            size--;
            return rightNode;
        }
        removeMin(node.left);
        return node;//返回删除最小节点后二叉树新的根
    }
    //删除二叉树最大值所在的节点并返回这个值
    public E removeMax(){
        E ret=maximum();
        root=removeMax(root);
        return ret;
    }
    private Node removeMax(Node node){
        if(node.right==null){
            Node leftNode=node.left;
            node.left=null;
            size--;
            return leftNode;
        }
        removeMax(node.right);
        return node;
    }
    //删除树中任意位置的节点
    //思想：先找到这个要删除的节点，通过元素的比较来找该节点，找到该节点后需要对其判断该节点的左子树和右子树是否为空，或者都不为空，这三种情况分别进行操作
    public void remove(E e){
        root=remove(root,e);
    }
    private Node remove(Node node,E e){
        if(node==null){
            return null;
        }
        if(e.compareTo(node.e)<0){
            node.left=remove(node.left,e);
            return node;//返回新的二叉树的根
        }
        if(e.compareTo(node.e)>0){
            node.right=remove(node.right,e);
            return node;
        }
        else//e.compareTo(node.e)==0
        {
            if(node.left==null){
                Node rightNode=node.right;
                size--;
                node.right=null;
                return rightNode;//将rightNode的节点设为最新二叉树的根节点
            }
            if(node.right==null){
                Node leftNode=node.left;
                size--;
                node.left=null;
                return leftNode;
            }
            else{
                Node successor=new Node(minimum(node.right).e);//把改节点右子树的最小节点赋值给successor
                size++;
                successor.right=removeMin(node.right);//吧succssor的右子树设置为要删除节点的右子树
                successor.left=node.left;//把要删除的节点node的左子树赋值给successor的左子树
                node.left=node.right=null;//将要删除的左子树和右子树置空
                size--;
                return successor;
            }
        }
    }
}